/*
 * FizzBuzz.java
 * Jun 19, 2013 
 */
package com.jramoyo.fizzbuzz;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DecimalFormat;

/**
 * @author jramoyo
 */
public class FizzBuzz {
	private static final int RANGE = 100;
	private static final int ITERATIONS = 100000;

	private static DecimalFormat formatter = new DecimalFormat("#.##");

	public static void main(String[] args) {
		System.out.println("=== Round 1 ===\n");
		testPerformance(RANGE, ITERATIONS);
		System.out.println();

		System.out.println("=== Round 2 ===\n");
		testPerformance(RANGE, ITERATIONS);
		System.out.println();

		System.out.println("=== Round 3 ===\n");
		testPerformance(RANGE, ITERATIONS);
		System.out.println();

		System.out.println("=== Round 4 ===\n");
		testPerformance(RANGE, ITERATIONS);
		System.out.println();

		System.out.println("=== Round 5 ===\n");
		testPerformance(RANGE, ITERATIONS);
		System.out.println();
	}

	private static void testPerformance(int range, int iterations) {
		long start;

		long totalFizzBuzz1 = 0;
		for (int i = 0; i < iterations; i++) {
			start = System.nanoTime();
			fizzBuzz1(range);
			totalFizzBuzz1 += System.nanoTime() - start;
		}

		long totalFizzBuzz2 = 0;
		for (int i = 0; i < iterations; i++) {
			start = System.nanoTime();
			fizzBuzz2(range);
			totalFizzBuzz2 += System.nanoTime() - start;
		}

		long totalFizzBuzz3 = 0;
		for (int i = 0; i < iterations; i++) {
			start = System.nanoTime();
			fizzBuzz3(range);
			totalFizzBuzz3 += System.nanoTime() - start;
		}

		double aveFizzBuzz1 = totalFizzBuzz1 / (double) iterations;
		double aveFizzBuzz2 = totalFizzBuzz2 / (double) iterations;
		double aveFizzBuzz3 = totalFizzBuzz3 / (double) iterations;

		double maxAve = max(aveFizzBuzz1, aveFizzBuzz2, aveFizzBuzz3);

		System.out.println("Iterations: " + iterations);
		System.out.println("Range: " + range);

		System.out.println();
		System.out.println("- Totals -");
		System.out.println("Solution 1 = " + totalFizzBuzz1 + " ns.");
		System.out.println("Solution 2 = " + totalFizzBuzz2 + " ns.");
		System.out.println("Solution 3 = " + totalFizzBuzz3 + " ns.");

		System.out.println();
		System.out.println("- Averages -");
		System.out.println("Solution 1 = " + formatter.format(aveFizzBuzz1) + " ns.");
		System.out.println("Solution 2 = " + formatter.format(aveFizzBuzz2) + " ns.");
		System.out.println("Solution 3 = " + formatter.format(aveFizzBuzz3) + " ns.");

		System.out.println();
		System.out.println("- Statistics -");
		System.out.println("Solution 1 = " + formatter.format(diff(aveFizzBuzz1, maxAve)) + "% faster");
		System.out.println("Solution 2 = " + formatter.format(diff(aveFizzBuzz2, maxAve)) + "% faster");
		System.out.println("Solution 3 = " + formatter.format(diff(aveFizzBuzz3, maxAve)) + "% faster");
	}

	private static double diff(double n, double max) {
		return (((max - n) / max) * 100);
	}

	private static double max(double d1, double d2, double d3) {
		double max = d1;
		if (d2 > max)
			max = d2;
		if (d3 > max)
			max = d3;
		return max;
	}

	private static void fizzBuzz1(int n) {
		PrintWriter writer = new PrintWriter(new StringWriter());
		for (int i = 1; i <= n; i++) {
			boolean fizz = i % 3 == 0;
			boolean buzz = i % 5 == 0;
			if (fizz && buzz)
				writer.print("FizzBuzz");
			else if (fizz)
				writer.print("Fizz");
			else if (buzz)
				writer.print("Buzz");
			else
				writer.print(i);
		}
	}

	private static void fizzBuzz2(int n) {
		PrintWriter writer = new PrintWriter(new StringWriter());
		for (int i = 1; i <= n; i++) {
			boolean fizz = i % 3 == 0;
			boolean buzz = i % 5 == 0;
			if (!fizz && !buzz) {
				writer.print(i);
			} else {
				if (fizz && buzz)
					writer.print("FizzBuzz");
				else if (fizz)
					writer.print("Fizz");
				else
					writer.print("Buzz");
			}
		}
	}

	private static void fizzBuzz3(int n) {
		PrintWriter writer = new PrintWriter(new StringWriter());
		for (int i = 1; i <= n; i++) {
			boolean fizz = i % 3 == 0;
			boolean buzz = i % 5 == 0;
			if (!fizz && !buzz) {
				writer.print(i);
			} else {
				if (fizz)
					writer.print("Fizz");
				if (buzz)
					writer.print("Buzz");
			}
		}
	}
}
